#include "Criminisi.hpp"

Criminisi::Criminisi()
{
    //todo
}

Criminisi::~Criminisi()
{
    //todo
}

int Criminisi::calculateWS(float confidence, float data, int windowSize)
{
    return windowSize;
}

float Criminisi::calculatePriority(float data_term, float conf_term)
{
    return data_term * conf_term;
}

void Criminisi::visualize(cv::Mat &image_padded, cv::Mat &mask_padded, int windowSize)
{
    cv::imshow("result_criminisi", image_padded);
}

void Criminisi::precedure(cv::Mat &image_padded, cv::Mat &mask_padded)
{
    return;
}

void Criminisi::findCandidatePatch(cv::Mat &image_padded, cv::Mat &mask_padded, int i, int j, int windowSize, std::vector<std::pair<float, cv::Point2i>> &candidators)
{

    const float MAXFLOAT = 3.40282347e+38F;
    const int number = 1;
    int offset = windowSize / 2;
    float min_ssd = MAXFLOAT, ssd;

    // get the patch around the target
    cv::Range targetRowRange_padded(i - offset, i + offset + 1);
    cv::Range targetColRange_padded(j - offset, j + offset + 1);

    cv::Mat imageTemplate = image_padded.rowRange(targetRowRange_padded).colRange(targetColRange_padded);
    cv::Mat maskTemplate = mask_padded.rowRange(targetRowRange_padded).colRange(targetColRange_padded);
    cv::Mat maskTemplateInv;
    maskTemplate.convertTo(maskTemplateInv, CV_8U, -1, 1);
    cv::Mat candidSourcePatch;

    std::map<float, cv::Point2d> m;

    for (int k = windowSize; k < image_padded.rows - windowSize; ++k)
    {
        for (int l = windowSize; l < image_padded.cols - windowSize; ++l)
        {
            if (k - offset < windowSize / 2 + 1 || k + offset + 1 > image_padded.rows - windowSize / 2 - 1 || l - offset < windowSize / 2 + 1 || l + offset + 1 > image_padded.cols - windowSize / 2 - 1)
            {
                continue;
            }
            //check that this candidate source patch does not have overlap with target patch
            if (abs(k - i) < imageTemplate.rows || abs(l - j) < imageTemplate.cols)
            {
                // target and source patch overlap
                continue;
            }
            cv::Range candidSourceRowRange = cv::Range(k - offset, k + offset + 1);
            cv::Range candidSourceColRange = cv::Range(l - offset, l + offset + 1);

            cv::Scalar s = cv::sum(mask_padded.rowRange(candidSourceRowRange)
                                       .colRange(candidSourceColRange));
            if (s[0] > 0)
            {
                // target region overlaps with masked region
                continue;
            }
            candidSourcePatch = image_padded.rowRange(candidSourceRowRange)
                                    .colRange(candidSourceColRange);

            ssd = cv::norm(imageTemplate, candidSourcePatch, cv::NORM_L2, maskTemplateInv);

            m.insert(std::pair<float, cv::Point2d>(ssd, cv::Point2i(k, l)));
        }
    }

    std::map<float, cv::Point2d>::iterator iter = m.begin();
    for (int count = 0; count < number; count++, ++iter)
    {
        candidators.push_back(*iter);
    }
}

cv::Point2i Criminisi::findBestPatch(cv::Mat &image_padded, cv::Mat &mask_padded, int i, int j, int windowSize, std::vector<std::pair<float, cv::Point2i>> &candidators, cv::Point2f dxdy)
{
    return candidators.begin()->second;
}

void Criminisi::afterIteration(cv::Mat &image_padded, cv::Mat &mask_padded, cv::Mat &confidence_padded, cv::Mat &data_paddeed, int i, int j)
{
    return;
}